<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>函数式与面向对象编程</title>
<script type="text/javascript">
/*函数式的声明：
    //具名函数：
    function fun1(){
        alert("fun1");
    }
    //不具名函数（匿名函数，可赋值给一变量。）
    var fun2 = function(){
        alert("fun2");
    }
    fun1(); 
    fun2();

    (function(){alert("立即执行的匿名函数！")})();    //立即执行的匿名函数，在闭包时作用非常大！
*/

/*函数返回值：
  //函数有返回值后，就会跳出函数，不再继续往下执行！
    function fun4(){
        return true;    //执行完此段代码后跳出函数！
        alert("执行完return后的值！");//此句代码不执行！
    }
    alert(fun4());
*/    
  
/*函数中的arguments对象：
  //函数中arguments对象，用来保存参数列表中所有参数
  //arguments对象类似数组，可用下标访问！并有length属性！
    function fun5(a,b,c,d){
        alert(arguments);    //[object Arguments]
        alert(typeof arguments); //object
        alert(arguments.length); //5 传递的参数个数
        alert(arguments[1]); //1 下标访问对象中的值
        
        for(i in arguments){
            alert(arguments[i]);
        }
    }
    fun5(0,1,2,3,4); 

    function mag(){
        var s = '';
        for(var i in arguments){
            s += arguments[i]+"\n";
        }
        alert(s);
    }  
    function mag(){
        var s = [];
        for(var i in arguments){
            s.push(arguments[i]);
        }
        alert(s.join("\n"));
    }    
    mag(1,2,3,4);
*/

/*使用arguments对象模拟函数重载：
    function fnTest(){
        var args = arguments;
        switch(arguments.length){
            case 0:
                return "没有输入参数！";
            case 1:
                return "输入了一个参数："+args[0];
            case 2:
                return "输入了两个参数："+args[0]+"和"+args[1]
        }
    }
    alert(fnTest());
    alert(fnTest(1));
    alert(fnTest(1,2));
*/

/*递归函数：
  //arguments.callee(); 在函数内部引用函数自身
    function fac(n){    //面向过程
        for(var i=ret=1; i<=n; i++){
            ret = ret*i;
        }        
        return ret;
    }
    function funFac(n){ //面向对象
       return n?n*arguments.callee(n-1):1;  //以后修改函数名时，不用查找函数体中的函数名了！
    }
    alert(fac(5));    //120
    alert(funFac(5)); //120
*/  
  
/*函数式编程caller属性：
      返回调用此函数的函数：[如果函数A调用函数B，那么B.caller(必须写在函数B的函数体中！)则会返回函数A]
    function B(){
        alert("函数B被函数A调用，将会返回函数A:"+"\n"+B.caller);
    }
    function A(){
        B();
    }
    A();
*/    

/*函数式编程重点：
 * 闭包：函数可以使用函数之外定义的变量！
 * 解释：在函数声明处向函数外部看到的所有已声明的变量，在函数内部都能访问到他的最终值！最终值！
  //最简单闭包：
    var str = "我是全局变量。";
    function fun(){
        alert(str);
    }
    //un();

  //复杂[函数嵌套]：
    function f1(){
        var str1 = "我是f1的局部变量!";
        alert(str);
        alert(str1);
        f2();
        function f2(){
            var str2 = "我是f2的局部变量!!";
            alert(str);
            alert(str2);
            f3(); 
            function f3(){
                var str3 = "我是f3的局部变量!!!";
                alert(str);
                alert(str3);
            }
        }
    }
  //f1();
   
  //闭包访问闭包外的值，并设置：
    function setValue(){
        var num = 123;
        return{
            get:function(){return num},
            set:function(value){num=value}
        }
    }
    var closure = setValue();
    //alert(setValue().get());
    //closure.set(2);
    //alert(closure.get());
*/ 
 
/*对象，创建构造函数：
  //创建一个对象：
    var obj = new Object();
    alert(obj);    //[object Object] 一个对象
    alert(Object); //function Object(){[native,code]} 一个函数
    Object();      //可直接执行      
  //构造函数可以是一个普通函数:
    function Demo(){} 
    var d = new Demo(); //new关键字创建一个对象的实例
    alert(d);     //[object Object] 对象实例化后的对象
   
  //this关键字的用法：  [未new之前指向window,new之后指向新的对象!]
    function this1(){
        this.name = 'liyifei';
    }
    alert(window.name);  //liyifei [未实例化前，name为window对象的属性！this指向window]
    var this1New = new this1();
    alert(this1New.name);//liyifei [实例化后，name是新对象的属性！this指向新对象]
    alert(window.name);  //liyifei [实例化后，window对象的name属性依然存在！this指向window]
 
  //给构造函数传参数，并通过参数给属性赋值：
    function mess(name,age){
        this.name = name;
        this.age  = age;
    }
    var messNew = new mess("liyifei",21);
    alert(messNew.name);//liyifei
    alert(messNew.age); //21

   //instanceof运算符：[判断对象是否是某个类的实例]
     function fun1(){}
     var fun2 = new fun1();
     alert(fun2 instanceof fun1);//true[判断fun2是否是fun1的实例]
     alert(fun1 instanceof fun2);//错误时无返回值！
*/

/*
面向对象术语：
        一种面向对象语言需要向开发者提供四种基本能力：
                封装——把相关的信息（无论数据或方法）存储在对象中的能力。
                聚集——把一个对象存储在另一个对象内的能力。
                继承——由另一个类（或多个类）得来类的属性和方法的能力。
                多态——编写能以多种方法运行的函数或方法的能力。
                
!!ECMAScript支持这些要求，因此可被看作面向对象的!!
*/

/*封装：
  //封装与私有属性：封装并不要求私有！
    function Person(name,age) {
        this.name = name;   //将值存储为对象的属性即是封装
        this.age = age;
    }
    var p1 = new Person("CJ",18);
  
  //目前ECMAScript并不支持私有属性，可通过闭包来实现：
    function pri(name,age){
        this.getName = function(){return name};
        this.setName = function(value){name = value};
        this.getAge  = function(){return age};
        this.setAge  = function(value){age  = value};
    }
    var priNew = new pri("liyifei",21);
    //alert(priNew.name); //undefined
    //alert(priNew.getName()); //liyifei
    
    priNew.setName("唐");
    //alert(priNew.getName()); //唐
*/

/*继承：*/

  //prototype属性:
    function inherit(name,age){
        this.name = name;
        this.age  = age;        
    }
    var inheritNew = new inherit("liyifei",21);
    //alert(inheritNew.name);
    //alert(inheritNew.age);
    inherit.prototype.love = "唐";
    //alert(inheritNew.love); //所有inherit对象的实例都继承了love属性

  //isPrototypeOf()方法：[每个对象都有此方法，判断是不是另一个对象的原型]
    function A(){}
    var B = new A();
    //alert(A.prototype.isPrototypeOf(B)); //true
  
/*对象冒充：

  //call方法：  
   function Demo(arg) {
        return this.name = arg;
    }
    var obj = new Object();
    Demo.call(obj,"name");
    //alert(obj.name); //"name"
*/    
  
    
</script>
</head>

<body>
<div id="div" style="width: 200px; height: 100px; border: 1px solid;"></div>
    
<script type="text/javascript">

</script> 
   
</body>
</html>